using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using ALib;
using ALib.Data.CSVOperation;
using ALib.Data.IO;
using ALib.Misc;
using DateTimeConverter = ALib.DateTimeConverter;

namespace TradingPlatform.Installer
{
    public partial class TradingPlatformInstaller : Form
    {
        public TradingPlatformInstaller()
        {
            InitializeComponent();
        }

        private void textBoxSourcePath_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
            {
                e.Effect = DragDropEffects.All;
            }
        }

        private void textBoxSourcePath_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
            if (files != null)
            {
                foreach (string file in files)
                {
                    textBoxSourcePath.Text = file;
                }
            }
        }

        private void textBoxDestinationPath_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
            {
                e.Effect = DragDropEffects.All;
            }
        }

        private void textBoxDestinationPath_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
            if (files != null)
            {
                foreach (string file in files)
                {
                    textBoxDestinationPath.Text = file;
                }
            }
        }

        private void buttonInstall_Click(object sender, EventArgs e)
        {
            GoodValue.Assert(Directory.Exists(textBoxSourcePath.Text));
            GoodValue.Assert(Directory.Exists(textBoxDestinationPath.Text));
            GoodValue.Assert(new DirectoryInfo(textBoxDestinationPath.Text).GetFiles().Length == 0);
            GoodValue.Assert(new DirectoryInfo(textBoxDestinationPath.Text).GetDirectories().Length == 0);

            // Read data.
            DirectoryInfo destinationDir = new DirectoryInfo(textBoxDestinationPath.Text);

            string sourceTradingPlatformPath = textBoxSourcePath.Text + @"\TradingClient";

            List<string[]> portRecords = CSVEditor.Open(textBoxSourcePath.Text + @"\Port.csv");
            Dictionary<string, string[]> portList = new Dictionary<string, string[]>();
            foreach (string[] portRecord in portRecords)
            {
                portList.Add(string.Format(@"{0}@{1}@{2}", portRecord[0], portRecord[1], portRecord[2]), portRecord);
            }

            string sourceExchangeRatePath = textBoxSourcePath.Text + @"\ExchangeRate.csv";

            string sourceTradingKernelPath = textBoxSourcePath.Text + @"\TradingKernel.txt";

            List<string[]> tickerInfoRecords = CSVEditor.Open(textBoxSourcePath.Text + @"\NewTickerInfo.csv");
            Dictionary<string, List<string[]>> tickerInfoSetList = new Dictionary<string, List<string[]>>();
            foreach (string[] tickerInfoRecord in tickerInfoRecords)
            {
                string symbol = tickerInfoRecord[(int)TickerInfoItemType.strategySymbol];
                if (!tickerInfoSetList.ContainsKey(symbol))
                {
                    tickerInfoSetList.Add(symbol, new List<string[]>());
                }
                tickerInfoSetList[symbol].Add(tickerInfoRecord);
            }

            List<DistricutionItem> districutionItemList = FormDistributionItemList(destinationDir, sourceTradingPlatformPath, portList, sourceExchangeRatePath, sourceTradingKernelPath, tickerInfoSetList);

            SaveDistributions(districutionItemList);


            GenerateBatch(destinationDir);

            MessageBox.Show("Finished");
        }

        private List<DistricutionItem> FormDistributionItemList(DirectoryInfo destinationDir, string sourceTradingPlatformPath, Dictionary<string, string[]> portList, string sourceExchangeRatePath, string sourceTradingKernelPath, Dictionary<string, List<string[]>> tickerInfoSetList)
        {
            // Form distribution item list.
            List<DistricutionItem> result = new List<DistricutionItem>();
            foreach (KeyValuePair<string, string[]> strategy_PortItems in portList)
            {
                string symbolIpPort = strategy_PortItems.Key;
                string[] portItems = strategy_PortItems.Value;
                string symbol = portItems[0];

                if (tickerInfoSetList.ContainsKey(symbol))
                {
                    List<string[]> tickerInfoSet = tickerInfoSetList[symbol];

                    DistricutionItem districutionItem = new DistricutionItem();

                    string destinationPath = destinationDir.FullName + @"\" + symbolIpPort;

                    districutionItem._symbolIpPort = symbolIpPort;

                    //public string _destinationConfigurationPath;
                    districutionItem._destinationConfigurationPath = destinationPath + @"\Configuration";

                    //public string _sourceTradingPlatformPath;
                    districutionItem._sourceTradingPlatformPath = sourceTradingPlatformPath;

                    //public string _destinationTradingPlatformPath;
                    districutionItem._destinationTradingPlatformPath = destinationPath;

                    //public string _sourceExchangeRatePath;
                    districutionItem._sourceExchangeRatePath = sourceExchangeRatePath;

                    //public string _destinationExchangeRatePath;
                    districutionItem._destinationExchangeRatePath = districutionItem._destinationConfigurationPath + @"\ExchangeRate.csv";

                    //public string _sourceTradingKernelPath;
                    districutionItem._sourceTradingKernelPath = sourceTradingKernelPath;

                    //public string _destinationTradingKernelPath;
                    districutionItem._destinationTradingKernelPath = districutionItem._destinationConfigurationPath + @"\TradingKernel.txt";

                    //public string _sourceBrokerString;
                    districutionItem._sourceBrokerString = string.Format(@"IP={0}
PORT={1}
CLIENT_ID={2}",
                                                                         portItems[(int)PortItemType.TradingApiIp],
                                                                         portItems[(int)PortItemType.TradingApiPort],
                                                                         portItems[(int)PortItemType.TradingApiClientId
                                                                             ]);

                    //public string _destinationBrokerPath;
                    districutionItem._destinationBrokerPath = districutionItem._destinationConfigurationPath + @"\ConnectionToIb.txt";

                    //public string _sourceStrategyString;
                    districutionItem._sourceStrategyString = string.Format(@"IP={0}
PORT={1}",
                                                                           portItems[(int)PortItemType.StrategyServerIp],
                                                                           portItems[(int)PortItemType.StrategyServerPort]);

                    //public string _destinationStrategyPath;
                    districutionItem._destinationStrategyPath = districutionItem._destinationConfigurationPath + @"\ConnectionToStrategy.txt";

                    //public string _sourceTickerInfoString;
                    districutionItem._sourceTickerInfoSet = GetNewTickerInfoSet(tickerInfoSet);

                    //public string _destinationTickerInfoPath;
                    districutionItem._destinationTickerInfoPath = districutionItem._destinationConfigurationPath + @"\TickerInfo.csv";

                    result.Add(districutionItem);
                }
            }
            return result;
        }

        private void GenerateBatch(DirectoryInfo destinationDir)
        {
            // Generate batch.
            DirectoryInfo[] destinationTradingClientDirs = destinationDir.GetDirectories();
            string batchString = "";
            foreach (DirectoryInfo destinationTraderDir in destinationTradingClientDirs)
            {
                batchString += string.Format(@"cd {0}", destinationTraderDir.Name) + "\r\n";
                batchString += @"start TradingPlatform.IB.TradingClient.exe" + "\r\n";
                //batchString += "pause\r\n";
                batchString += "cd ..\r\n\r\n";
            }

            using (StreamWriter sw = new StreamWriter(textBoxDestinationPath.Text + @"\Start.bat"))
            {
                sw.Write(batchString);
            }

            using (StreamWriter sw = new StreamWriter(textBoxDestinationPath.Text + @"\End.bat"))
            {
                sw.Write("taskkill /f /im TradingPlatform.IB.TradingClient.exe");
            }
        }

        private static void SaveDistributions(List<DistricutionItem> districutionItemList)
        {
            // Save to destination.
            foreach (DistricutionItem districutionItem in districutionItemList)
            {
                //public string _sourceTradingPlatformPath;
                //public string _destinationTradingPlatformPath;
                Dir.CopyFolder(new DirectoryInfo(districutionItem._sourceTradingPlatformPath), new DirectoryInfo(districutionItem._destinationTradingPlatformPath), false);

                Dir.CreateFolder(new DirectoryInfo(districutionItem._destinationConfigurationPath), true);
                //public string _sourceExchangeRatePath;
                //public string _destinationExchangeRatePath;
                File.Copy(districutionItem._sourceExchangeRatePath, districutionItem._destinationExchangeRatePath);

                //public string _sourceTradingKernelPath;
                //public string _destinationTradingKernelPath;
                File.Copy(districutionItem._sourceTradingKernelPath, districutionItem._destinationTradingKernelPath);

                // Change the data path of trading kernel file.
                Configuration configuration = new Configuration(districutionItem._destinationTradingKernelPath);
                string oldDataPath = configuration.GetString(KeyWordsTradingKernel.DataPath);
                string newDataPath = oldDataPath.TrimEnd(new char[] { '\\' }) + @"\" + districutionItem._symbolIpPort;
                configuration.ResetAttribute(KeyWordsTradingKernel.DataPath, newDataPath);
                configuration.Save();

                //public string _sourceBrokerString;
                //public string _destinationBrokerPath;
                using (StreamWriter sw = new StreamWriter(districutionItem._destinationBrokerPath))
                {
                    sw.Write(districutionItem._sourceBrokerString);
                }

                //public string _sourceStrategyString;
                //public string _destinationStrategyPath;
                using (StreamWriter sw = new StreamWriter(districutionItem._destinationStrategyPath))
                {
                    sw.Write(districutionItem._sourceStrategyString);
                }

                //public List<string[]> _sourceTickerInfoSet;
                //public string _destinationTickerInfoPath;   
                CSVEditor.Save(districutionItem._sourceTickerInfoSet, districutionItem._destinationTickerInfoPath);
            }
        }

        private List<string[]> GetNewTickerInfoSet(List<string[]> tickerInfoSet)
        {
            GoodValue.Assert(tickerInfoSet != null && tickerInfoSet.Count > 0);
            int minContractMonth = 999999;
            foreach (string[] tickerInfo in tickerInfoSet)
            {
                int month = int.Parse(tickerInfo[(int)TickerInfoItemType.expiry]);
                if (month < minContractMonth)
                {
                    minContractMonth = month;
                }
            }
            DateTime startingMonth = DateTimeConverter.ToDate(minContractMonth + "01");

            List<string[]> result = new List<string[]>();
            for (int i = -3; i < 0; i++)
            {
                DateTime newMonth = startingMonth.AddMonths(i);
                string newMonthString = newMonth.ToString("yyyyMM");

                string[] tickerInfoTemplate = new string[tickerInfoSet[0].Length];
                tickerInfoSet[0].CopyTo(tickerInfoTemplate, 0);
                tickerInfoTemplate[(int)TickerInfoItemType.expiry] = newMonthString;
                result.Add(tickerInfoTemplate);
            }

            foreach (string[] tickInfo in tickerInfoSet)
            {
                result.Add(tickInfo);
            }

            return result;
        }
    }
}